package com.geh.learn.thread.completablefuture;

import java.util.concurrent.*;

import static com.geh.learn.thread.completablefuture.AllOfExample.delayedUpperCase;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertEquals;

public class CompleteFeatureTest {

    public static void p(Object s) {
        System.out.println(s);
    }

    public static void test001() {
        CompletableFuture cf = CompletableFuture.completedFuture("message");
        p(cf.isDone());
        p(cf.getNow(null));
    }

    public static void test002() {
        CompletableFuture cf = CompletableFuture.runAsync(() -> {
            p(Thread.currentThread().isDaemon());

            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });

        p(cf.isDone());

        try {
            TimeUnit.SECONDS.sleep(12);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        p(cf.isDone());
    }

    static void test003() {
        CompletableFuture cf = CompletableFuture.completedFuture("message").thenApply(s -> {
            p(Thread.currentThread().isDaemon());
            return s.toUpperCase();
        });
        p(cf.getNow(null));
    }

    static void test004() {
        CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
            p(Thread.currentThread().isDaemon());

            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return s.toUpperCase();
        });

        p(cf.getNow(null));

        p(cf.join());
    }

    static ExecutorService executor = Executors.newFixedThreadPool(3, new ThreadFactory() {
        int count = 1;

        @Override
        public Thread newThread(Runnable runnable) {
            return new Thread(runnable, "custom-executor-" + count++);
        }
    });

    static void test005() {
        CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
            p(Thread.currentThread().getName().startsWith("custom-executor-"));
            p(Thread.currentThread().isDaemon());

            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return s.toUpperCase();
        }, executor);

        p(cf.getNow(null));
        p(cf.join());
    }

    static void test006() {
        StringBuilder result = new StringBuilder();
        CompletableFuture.completedFuture("thenAccept message").thenAccept(s -> result.append(s));
        p(result);
    }

    static void test007() {
        StringBuilder result = new StringBuilder();
        CompletableFuture cf = CompletableFuture.completedFuture("thenAcceptAsync message")
                .thenAcceptAsync(s -> result.append(s));
        // 异步执行，所以需要join一下
        cf.join();
        p(result.length() > 0);
    }

    static void test008() {
        CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(String::toUpperCase, CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS));

        CompletableFuture exceptionHandler = cf.handle((s, th) -> { return (th != null) ? "message upon cancel" : ""; });

        cf.completeExceptionally(new RuntimeException("completed exceptionally"));

        p("Was not completed exceptionally : " + cf.isCompletedExceptionally());
        try {
            cf.join();
            p("Should have thrown an exception");
        } catch(CompletionException ex) {
            // just for testing
            p("completed exceptionally : " + ex.getCause().getMessage());
        }

        p("message upon cancel : " + exceptionHandler.join());
    }

    static void test009() {
        CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(String::toUpperCase, CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS));
        CompletableFuture cf2 = cf.exceptionally(throwable -> "canceled message");

        p("Was not canceled : " + cf.cancel(true));

        p("Was not completed exceptionally : " + cf.isCompletedExceptionally());

        p("canceled message : " + cf2.join());
    }

//    static void test010() {
//        String original = "Message";
//        CompletableFuture cf1 = CompletableFuture.completedFuture(original)
//                .thenApplyAsync(s -> delayedUpperCase(s));
//        CompletableFuture cf2 = cf1.applyToEither(
//                CompletableFuture.completedFuture(original).thenApplyAsync(s -> delayedLowerCase(s)),
//                s -> s + " from applyToEither");
//        assertTrue(cf2.join().endWith(" from applyToEither"));
//    }

    public static void main(String[] args) {
        test009();
    }

}
